﻿namespace SsisLdapSource
{
    using System;
    using System.Data;
    using System.DirectoryServices.Protocols;

    using Microsoft.SqlServer.Dts.Pipeline;
    using InstantiationTime;
    using Microsoft.SqlServer.Dts.Pipeline.Wrapper;

    using global::SsisLdapSource.DirectoryServicesProtocolsExtensions;

    [DtsPipelineComponent(
        DisplayName = "LDAP Source",
        ComponentType = ComponentType.SourceAdapter)]
    public partial class SsisLdapSource : PipelineComponent
    {
        public override void ProvideComponentProperties()
        {
            RemoveAllInputsOutputsAndCustomProperties();
            ComponentMetaData.RuntimeConnectionCollection.RemoveAll();

            var customPropertiesFactory = new CustomPropertiesInitializer(ComponentMetaData);
            customPropertiesFactory.AddCustomProperties();

            var sourceComponentOutput = ComponentMetaData.OutputCollection.New();
            sourceComponentOutput.Name = "output";
        }

        public override void SetOutputColumnDataTypeProperties(
            int outputID,
            int outputColumnID,
            Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType dataType,
            int length,
            int precision,
            int scale,
            int codePage)
        {
            var outputColl = ComponentMetaData.OutputCollection;
            var output = outputColl.GetObjectByID(outputID);
            var columnColl = output.OutputColumnCollection;
            var column = columnColl.GetObjectByID(outputColumnID);
            column.SetDataTypeProperties(dataType, length, precision, scale, codePage);
        }

        public override DTSValidationStatus Validate()
        {
            ValidateCustomProperties();
            LdapConnection.TestConnectivity();
            // in this stage semantic interpritation is not required so sending empty InitValues
            var ldapMetaMapFactoryInitializationValues = new LdapMetaMapFactoryInitializationValues();
            var ldapMetaMapFactory = new LdapMetaMapFactory(ldapMetaMapFactoryInitializationValues);
            PagedSearchRequest.PreExecuteTest(LdapConnection, ldapMetaMapFactory);
            ValidateColumns();
            return DTSValidationStatus.VS_ISVALID; // if we got here, then no exceptions were thrown by validation methods
        }

        public override void ReinitializeMetaData()
        {
           ComponentMetaData.OutputCollection[0].OutputColumnCollection.RemoveAll();
           CreateOutputColumnsBasedOnActiveDirectorySchema();
        }

        public override void PreExecute()
        {
            GenerateColumnsRunTimeInfo();
        }

        public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] pipelineBuffers)
        {
            var runTimeLdapConnection = LdapConnection; // will reuse the same connection object
            var ldapMetaMapFactoryInitializationValues = new LdapMetaMapFactoryInitializationValues(
                GuidEncodedAttributeBinaryAttributes,
                SidEncodedAttributeBinaryAttributes,
                Int64EncodedAttributeDateTimeAttributes,
                StringEncodedIntAttributes,
                AttributesWhichMayRequireExpansion);
                
            var ldapMetaMapFactory = new LdapMetaMapFactory(ldapMetaMapFactoryInitializationValues);
            var pipelineBuffer = pipelineBuffers[0];
            var dataTableBuffer = PagedSearchRequest.BuildDataTableToHoldResults(runTimeLdapConnection, ldapMetaMapFactory);

            foreach (var searchResultEntryCollection in PagedSearchRequest.Execute(runTimeLdapConnection))
            {
                foreach (SearchResultEntry searchResultEntry in searchResultEntryCollection)
                {
                    dataTableBuffer.Rows.Clear();
                    searchResultEntry.ToDataTable(
                        runTimeLdapConnection,
                        ldapMetaMapFactory,
                        dataTableBuffer,
                        UniqueObjectIdentifierAttribute);
                    foreach (DataRow dataTableBufferRow in dataTableBuffer.Rows)
                    {
                        pipelineBuffer.AddRow();
                        foreach (DataColumn dataTableBufferColumn in dataTableBuffer.Columns)
                        {
                            if (dataTableBufferRow[dataTableBufferColumn.ColumnName] != DBNull.Value)
                            {
                                pipelineBuffer[runTimeColumnsInfo[dataTableBufferColumn.ColumnName]] =
                                    dataTableBufferRow[dataTableBufferColumn.ColumnName];
                            }
                            else
                            {
                                pipelineBuffer.SetNull(runTimeColumnsInfo[dataTableBufferColumn.ColumnName]);
                            }
                        }
                    }
                }
            }

            pipelineBuffer.SetEndOfRowset();
        }
    }
}
